#pragma once

#include <zenox/minilog.hpp>
#include <array>
#include <string>
#include <glm/glm.hpp>
#include <glm/ext.hpp>

template <typename T, glm::length_t N>
struct ZENO_MINILOG_FMT_NAMESPACE::formatter<glm::vec<N, T>> {
private:
    formatter<T> m_component;
    formatter<std::string> m_string;

public:
    constexpr auto parse(format_parse_context &ctx) {
        return m_component.parse(ctx);
    }

    constexpr auto format(glm::vec<N, T> const &vec, format_context &ctx) const {
        m_string.format("{", ctx);
        for (glm::length_t i = 0; i < N; ++i) {
            m_component.format(vec[i], ctx);
            if (i + 1 != N)
                m_string.format(", ", ctx);
        }
        return m_string.format("}", ctx);
    }
};

namespace zenox {

template <class T>
struct glm_traits {
    using value_type = T;
    inline static constexpr bool is_mat = false;
    inline static constexpr bool is_vec = false;
    inline static constexpr bool is_scalar = true;
    inline static constexpr glm::length_t components = 1;
    inline static constexpr glm::length_t columns = 1;
    inline static constexpr glm::length_t rows = 1;
};

template <class T, glm::length_t N>
struct glm_traits<glm::vec<N, T>> {
    using value_type = T;
    inline static constexpr bool is_mat = false;
    inline static constexpr bool is_vec = true;
    inline static constexpr bool is_scalar = false;
    inline static constexpr glm::length_t components = N;
    inline static constexpr glm::length_t columns = N;
    inline static constexpr glm::length_t rows = 1;
};

template <class T, glm::length_t N, glm::length_t M>
struct glm_traits<glm::mat<N, M, T>> {
    using value_type = T;
    inline static constexpr bool is_mat = true;
    inline static constexpr bool is_vec = false;
    inline static constexpr bool is_scalar = false;
    inline static constexpr glm::length_t components = N * M;
    inline static constexpr glm::length_t columns = N;
    inline static constexpr glm::length_t rows = M;
};

}
